using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Html;
using System.Runtime.CompilerServices;
using Awaiter;
using Nsb.Classes;
using Theme;
using Yoshi.Classes;
using YoshiBase.Classes;
using jQueryApi;

namespace Yoshi.Clusters
{
    [IgnoreNamespace]
    public class AlivenessBubble : Actor
    {
        private readonly FeedItem _item;
        // ReSharper disable UnusedMember.Local
        private readonly bool _liveEventsAdded = AddLiveEvents();
        private readonly jQueryObject _text;
        // ReSharper restore UnusedMember.Local

        private AlivenessBubble(jQueryObject appendEl, FeedItem item)
        {
            _item = item;

            Element = jQuery.FromHtml("<div class='AlivenessBubble'/>")
                .Data("itemId", item.id)
                ;

            _text = jQuery.FromHtml("<p/>")
                .AppendTo(Element)
                .Html("<span class='Quote'>&hearts; &ldquo;</span>" + item.message + "<span class='Quote'>&rdquo;</span>")
                .Data("msg", item.message)
                ;

            jQuery.FromHtml("<div class='ActionBtn LikeBtn'/>")
                .AppendTo(_text)
                .Html(SiteTheme.Smile)
                .Attribute("title", SiteTheme.LikeBtnTitle)
                .Click(AddLike)
                ;

            jQuery.FromHtml("<div class='ActionBtn CommentBtn'/>")
                .AppendTo(_text)
                .Html(SiteTheme.Clubs)
                .Attribute("title", SiteTheme.CommentBtnTitle)
                .Click(MakeComment)
                ;

            jQuery.FromHtml("<div class='ActionBtn StreamBtn'/>")
                .AppendTo(_text)
                .Html(SiteTheme.Hearts)
                .Attribute("title", SiteTheme.StreamBtnTitle)
                .Click(AddToStream)
                ;

            jQuery.FromHtml("<div class='ActionBtn EditBtn'/>")
                .AppendTo(_text)
                .Html(SiteTheme.Diamonds)
                .Attribute("title", SiteTheme.EditBtnTitle)
                .Click(EditComment)
                ;

            Element.AppendTo(appendEl);

            if (item.hasComments)
                new Await()
                    .AddAw(CommentData.NewGetAw, item.id)
                    .HandleDl(Exceptions.BlobLoadError, Await.AbortAw)
                    .AddAw(AttachCommentsAw)
                    .Commit();
        }

        public void AttachCommentsAw(Await awp)
        {
            List<CommentItem> comments = (List<CommentItem>) awp["result"];
            if (comments != null)
            {
                jQueryObject cbx = jQuery.FromHtml("<div/>")
                    .InsertAfter(Element)
                    ;
                foreach (CommentItem i in comments)
                {
                    CommentBubble.InsertCommentAw(Await.AsyncAw, cbx, i);
                }
            }
        }

        /// <summary>
        /// Creates an animated aliveness bubble.
        /// </summary>
        /// <param name="el">jQueryObject where animation starts</param>
        /// <param name="item">The feed item.</param>
        /// <returns></returns>
        public static AlivenessBubble Nue(jQueryObject el, FeedItem item)
        {
            return new AlivenessBubble(el, item);
        }

        public static void AnimateBubbleAw(Await awp, string msg, jQueryObject assocEl)
        {
            Nue(jQuery.FromObject(Document.Body), new FeedItem(FeedItem.TextCategory, msg)).AnimateFrom(awp, assocEl);
        }

        public AlivenessBubble AnimateFrom(Await awp, jQueryObject hereEl)
        {
            Element.CSS(
                new Dictionary(
                    "position", "absolute",
                    "z-index", SiteTheme.ZIndexHider + 1,
                    "top", hereEl.GetOffset().Top - 10,
                    "left", hereEl.GetOffset().Left - 10
                    )
                );

            new Await()
                .AddDx(
                    delegate
                    {
                        _text.CSS("overflow", "hidden").CSS("white-space", "nowrap");
                        Element.CSS("overflow", "hidden").CSS("white-space", "nowrap").CSS("height", Element.GetHeight() + "px").CSS("padding", "20px 40px");
                        Element.Plugin<Jewl>().FitIntoWindow();
                    })
                .AddAw(AnimateAw,
                       new Dictionary(
                           "top", -10,
                           "left", 700,
                           "width", 30,
                           "height", 20,
                           "padding-top", "3px",
                           "padding-bottom", "3px",
                           "padding-left", "5px",
                           "padding-right", "5px",
                           "font-size", "3pt"
                           ),
                       new Dictionary("duration", 350, "easing", EffectEasing.Linear)
                )
                .AddDx(delegate { Element.Remove(); })
                .Commit(awp);
            return this;
        }

        //
        // TODO: Bug in that if you modify your feed in two different browsers the latest always wins.
        // Consider syncing browsers with http push channel (like google doc sharing) so that they can tell each other to update.
        //
        public void AddLike(jQueryEvent e)
        {
            Debug.Assert(Script.IsValue(_item), "_item has value");
            CancelEvent(e);
            new Await()
                .AddAw(new Ask().OkAw, "Like feature comming soon " + SiteTheme.Smile)
                //.AddAw(CommentBubble.NewAw, _item.id, Element)
                //.AddDx(delegate { _item.hasComments = true; })
                //.AddAw(Master.Profile.SaveFeedAw)
                //.AddAw(Master.UpdateFeedAw)
                .Commit();
        }

        public void MakeComment(jQueryEvent e)
        {
            Debug.Assert(Script.IsValue(_item), "_item has value");
            CancelEvent(e);
            new Await()
                .AddAw(CommentBubble.NewAw, _item.id, Element)
                .AddDx(delegate { _item.hasComments = true; })
                .AddAw(Master.Profile.SaveFeedAw)
                .AddAw(Master.UpdateFeedAw)
                .Commit();
        }

        public void AddToStream(jQueryEvent e)
        {
            CancelEvent(e);
            new Await()
                .AddAw(Master.Profile.WriteToFeedAw, FeedItem.TextCategory, (string) _text.GetDataValue("msg"))
                .AddAw(Master.UpdateFeedAw)
                .AddAw(AnimateBubbleAw, (string) _text.GetDataValue("msg"), jQuery.FromElement(e.Target))
                .Commit();
        }

        public void EditComment(jQueryEvent e)
        {
            Debug.Assert(Script.IsValue(_item), "_item has value");
            CancelEvent(e);
            new Await()
                .AddAw(AlivenessBubbleEdit.EditAw, Element, _item.message)
                .AddDx(delegate(Await aw) { _item.message = (string) aw[PkgBase.ResultRx]; })
                .AddAw(Master.Profile.SaveFeedAw)
                .AddAw(Master.UpdateFeedAw)
                .Commit();
        }

        private static bool AddLiveEvents()
        {
            jQuery.Select(".AlivenessBubble")
                .Live("mouseenter.alivenessbubble", ShowDelete)
                .Live("mouseleave.alivenessbubble", HideDelete)
                ;
            return true;
        }

        private static void ShowDelete(jQueryEvent e)
        {
            jQueryObject el = jQuery.FromElement(e.Target).Closest(".AlivenessBubble");
            jQuery.FromHtml("<div class='HiddenDeleteBtn'/>")
                .AppendTo(el)
                .Html("&spades;")
                .Attribute("title", SiteTheme.DeleteBtnTitle)
                .Click(
                    delegate(jQueryEvent e2)
                    {
                        Await awx = new Await();
                        if (!e2.ShiftKey)
                            awx
                                .AddAw(new Ask().OkCancelAw, SiteTheme.ForSure)
                                .AddAw(RequireResultAw, true)
                                ;
                        awx
                            .AddDx(
                                delegate
                                {
                                    CancelEvent(e2);
                                    Master.Profile.DeleteFeedItem((string) el.GetDataValue("itemId"));
                                })
                            .Commit();
                    })
                ;
        }

        private static void HideDelete(jQueryEvent e)
        {
            jQueryObject del = jQuery.Select(".HiddenDeleteBtn");
            if (del != null)
                del.Remove();
        }
    }

    //
    //
    //

    [IgnoreNamespace]
    public class AlivenessBubbleEdit : EditBase
    {
        private readonly jQueryObject _elIn;

        private AlivenessBubbleEdit(Await awp, jQueryObject el, string msg, string okFace)
        {
            AwpIn = awp;
            _elIn = el;
            Msg = msg;
            EscapeKeyAction(Cancel);
            ShiftRetKeyAction(Ok);

            Element = jQuery.FromHtml("<div class='AlivenessBubbleEdit EditBubble'/>")
                .CSS(
                    new Dictionary(
                        "top", el.GetOffset().Top - 10,
                        "left", el.GetOffset().Left - 10
                        )
                )
                ;

            BuildCommon();

            OkBtn.Html(okFace);
            CancelBtn.Html(SiteTheme.CancelBtnFace);

            Element.AppendTo(Document.Body);
            if (okFace == SiteTheme.AlivenessAddBtnFace)
                OkBtn.Focus();
            else
                Textarea.Focus();
            Hider(true);
            ScrollInViewAw(Await.AsyncAw, Element);
        }

        protected override void Destroy()
        {
            EscapeKeyAction();
            ShiftRetKeyAction();
            new Await()
                .AddAw(FadeOutAw, 80)
                .AddAw(RemoveAw)
                .AddDl(delegate(Await aw)
                       {
                           if (AwpIn["result"] != null)
                               AlivenessBubble.AnimateBubbleAw(aw, (string) AwpIn["result"], _elIn);
                           else
                               aw.Done();
                       })
                .AddFn(Hider, false)
                .Commit(AwpIn);
        }

        /// <summary>
        /// Creates an animated aliveness edit bubble.
        /// </summary>
        /// <param name="awp">The parent await object</param>
        /// <param name="el">jQueryObject where edit bubble pops</param>
        /// <param name="msg">message string</param>
        public static void NewAw(Await awp, object el, object msg)
        {
            new AlivenessBubbleEdit(awp, (jQueryObject) el, (string) msg, SiteTheme.AlivenessAddBtnFace);
        }

        public static void EditAw(Await awp, object el, object msg)
        {
            new AlivenessBubbleEdit(awp, (jQueryObject)el, (string)msg, SiteTheme.AlivenessEditBtnFace);
        }
    }
}